#ifndef _IDATABASE_H_
#define _IDATABASE_H_

//////////////////////////////////////////////////////////////////////////
typedef enum eFIELD_FLAG {
    FF_NOT_NULL = 0x00000001,
    FF_PRI_KEY = 0x00000002,
    FF_UNIQUE_KEY = 0x00000004,
    FF_MULTIPLE_KEY = 0x00000008,
    FF_UNSIGNED = 0x00000010,
    FF_ZEROFILL = 0x00000020,
    FF_BINARY = 0x00000040,
    FF_AUTO_INCREMENT = 0x00000080,
} FIELD_FLAG;

typedef enum eFIELD_TYPE {
    FT_UNKNOWN = 0x00001,
    FT_BIT,
    FT_TINYINT,
    FT_SMALLINT,
    FT_MEDIUMINT,
    FT_INT,
    FT_INTEGER,
    FT_BIGINT,
    FT_REAL,
    FT_DOUBLE,
    FT_FLOAT,
    FT_DECIMAL,
    FT_NUMERIC,
    FT_DATE,
    FT_TIME,
    FT_TIMESTAMP,
    FT_DATETIME,
    FT_YEAR,
    FT_CHAR,
    FT_VARCHAR,
    FT_BINARY,
    FT_VARBINARY,
    FT_TINYBLOB,
    FT_BLOB,
    FT_MEDIUMBLOB,
    FT_LONGBLOB,
    FT_TINYTEXT,
    FT_TEXT,
    FT_MEDIUMTEXT,
    FT_LONGTEXT,
    FT_ENUM,
    FT_SET,
    FT_GEOMETRY,
    FT_NULL,
} FIELD_TYPE;

static_inline int sqlite_string_to_type(const char* strTypeName)
{
    if (string_stricmp("INT", strTypeName) == 0 || string_stricmp("INT2", strTypeName) == 0 || string_stricmp("INT8", strTypeName) == 0) {
        return FT_INT;
    } else if (string_stricmp("TINYINT", strTypeName) == 0) {
        return FT_TINYINT;
    } else if (string_stricmp("SMALLINT", strTypeName) == 0) {
        return FT_SMALLINT;
    } else if (string_stricmp("MEDIUMINT", strTypeName) == 0) {
        return FT_MEDIUMINT;
    } else if (string_stricmp("INTEGER", strTypeName) == 0) {
        return FT_INTEGER;
    } else if (string_stricmp("BIGINT", strTypeName) == 0) {
        return FT_BIGINT;
    } else if (strstr(strTypeName, "CHAR") != NULL || string_stricmp("TEXT", strTypeName) == 0 || string_stricmp("CLOB", strTypeName) == 0) {
        return FT_TEXT;
    } else if (string_stricmp("BLOB", strTypeName) == 0) {
        return FT_BLOB;
    } else if (string_stricmp("REAL", strTypeName) == 0) {
        return FT_REAL;
    } else if (strstr(strTypeName, "DOUBLE") != NULL) {
        return FT_DOUBLE;
    } else if (string_stricmp("FLOAT", strTypeName) == 0) {
        return FT_FLOAT;
    } else if (string_stricmp("NUMERIC", strTypeName) == 0 || string_stricmp("BOOLEAN", strTypeName) == 0) {
        return FT_NUMERIC;
    } else if (strstr(strTypeName, "DECIMAL") != NULL) {
        return FT_DECIMAL;
    } else if (string_stricmp("DATE", strTypeName) == 0) {
        return FT_DATE;
    } else if (string_stricmp("DATETIME", strTypeName) == 0) {
        return FT_DATETIME;
    } else if (string_stricmp("NONE", strTypeName) == 0) {
        return FT_NULL;
    } else {
        return FT_UNKNOWN;
    }

    return FT_UNKNOWN;
}

interface IFieldInfo : public IBase
{
    std_method_(LPCSTR, GetName)() PURE;
    std_method_(UINT, GetFlag)() PURE;
    std_method_(LPCSTR, GetTypeName)() PURE;
    std_method_(int, GetType)() PURE;
    std_method_(ULONG, GetLength)() PURE;
    std_method_(LPCSTR, GetDefault)() PURE;
    std_method_(UINT, GetDecimals)() PURE;
    std_method(SetName)(LPCSTR lpszName) PURE;
    std_method(SetFlag)(UINT nFlag) PURE;
    std_method(SetType)(int nType) PURE;
    std_method(SetTypeName)(LPCSTR lpszType) PURE;
    std_method(SetLength)(unsigned long nLength) PURE;
    std_method(SetDefault)(LPCSTR lpszValue) PURE;
    std_method(SetDecimals)(unsigned int nDecimals) PURE;
};

// {91CF94B5-9257-4539-BF9D-D938766C9988}
_DEF_IID(IID_IFieldInfo, 0x91cf94b5, 0x9257, 0x4539, 0xbf, 0x9d, 0xd9, 0x38, 0x76, 0x6c, 0x99, 0x88);

interface ITableInfo : public IBase
{
    std_method_(LPCSTR, GetName)() PURE;
    std_method(Add)(IFieldInfo* pFieldInfo) PURE;
    std_method(Remove)(unsigned int nIndex) PURE;
    std_method_(ULONG, GetFieldCount)() PURE;
    std_method(GetField)(UINT nIndex, IFieldInfo** pField) PURE;
    std_method(CreateField)(IFieldInfo** pField) PURE;
    std_method(Remove)(LPCSTR lpszName) PURE;
    std_method(GetField)(LPCSTR lpszName, IFieldInfo** pField) PURE;
};

// {EE26DD9F-ABC6-49F5-8C06-1A84B8BA1C5F}
_DEF_IID(IID_ITableInfo, 0xee26dd9f, 0xabc6, 0x49f5, 0x8c, 0x6, 0x1a, 0x84, 0xb8, 0xba, 0x1c, 0x5f);

interface IRecordSet : public IBase
{
    std_method_(UINT, Next)() PURE;
    std_method_(UINT, Previous)() PURE;
    std_method_(UINT, First)() PURE;
    std_method_(UINT, Last)() PURE;
    std_method_(uint64, GetCount)() PURE;
    std_method_(ULONG, GetFieldCount)() PURE;
    std_method(GetInt)(unsigned int nIndex, INT& nValue) PURE;
    std_method(GetUInt)(unsigned int nIndex, UINT& nValue) PURE;
    std_method(GetInt64)(unsigned int nIndex, int64& nValue) PURE;
    std_method(GetUInt64)(unsigned int nIndex, uint64& nValue) PURE;
    std_method(GetFloat)(unsigned int nIndex, float& fValue) PURE;
    std_method(GetDouble)(unsigned int nIndex, double& dValue) PURE;
    std_method_(LPCSTR, GetString)(unsigned int nIndex) PURE;
    std_method_(const unsigned char*, GetBlob)(unsigned int nIndex) PURE;
    std_method(GetInt)(LPCSTR lpszName, INT& nValue) PURE;
    std_method(GetInt64)(LPCSTR lpszName, int64& nValue) PURE;
    std_method(GetUInt)(LPCSTR lpszName, UINT& nValue) PURE;
    std_method(GetUInt64)(LPCSTR lpszName, uint64& nValue) PURE;
    std_method(GetFloat)(LPCSTR lpszName, float& fValue) PURE;
    std_method(GetDouble)(LPCSTR lpszName, double& dValue) PURE;
    std_method_(LPCSTR, GetString)(LPCSTR lpszName) PURE;
    std_method_(const unsigned char*, GetBlob)(LPCSTR lpszName) PURE;
};

// {C567CCA6-A882-4638-8926-0486FE22D1BA}
_DEF_IID(IID_IRecordSet, 0xc567cca6, 0xa882, 0x4638, 0x89, 0x26, 0x4, 0x86, 0xfe, 0x22, 0xd1, 0xba);

interface IStatement : public IBase
{
    std_method(Query)(LPCSTR lpszSQL, UINT ulen, IRecordSet** pRecordSet) PURE;
    std_method_(int, Execute)(LPCSTR lpszSQL, UINT ulen) PURE;
    std_method_(int, Insert)(LPCSTR lpszSQL, UINT ulen) PURE;
    std_method(SetInt)(unsigned int nIndex, INT nValue) PURE;
    std_method(SetUInt)(unsigned int nIndex, UINT nValue) PURE;
    std_method(SetInt64)(unsigned int nIndex, int64 nValue) PURE;
    std_method(SetDouble)(unsigned int nIndex, double dbValue) PURE;
    std_method(SetFloat)(unsigned int nIndex, float fValue) PURE;
    std_method(SetBlob)(unsigned int nIndex, const unsigned char* lpszData, int nSize) PURE;
    std_method(SetString)(unsigned int nIndex, LPCSTR lpszData, int nSize) PURE;
    std_method(SetDateTime)(unsigned int nIndex, int64 nDateTime) PURE;
    std_method_(int, Commit)() PURE;
    std_method(Free)() PURE;
    std_method(Reset)() PURE;
};

// {717B694C-8DA0-4C6E-BEEF-CB091AD2338E}
_DEF_IID(IID_IStatement, 0x717b694c, 0x8da0, 0x4c6e, 0xbe, 0xef, 0xcb, 0x9, 0x1a, 0xd2, 0x33, 0x8e);

interface IDatabase : public IBase
{
    std_method(SetOption)(LPCWSTR lpszName, LPCWSTR lpszValue) PURE;
    std_method(Connect)() PURE;
    std_method_(UINT, IsValid)() PURE;
    std_method(Close)() PURE;
    std_method(CreateStatement)(IStatement** ppStatement) PURE;
    std_method_(UINT, IsTableExist)(LPCSTR lpszName) PURE;
    std_method(GetTableInfo)(LPCSTR lpszName, ITableInfo** ppTableInfo) PURE;
    std_method(UpdateTable)(ITableInfo* pTableInfo) PURE;
    std_method(CreateTableInfo)(LPCSTR lpszName, ITableInfo** ppTableInfo) PURE;
};

// {F4EAEEFA-0F74-4294-A5C9-8B29B5EAFA37}
_DEF_IID(IID_IDatabase, 0xf4eaeefa, 0xf74, 0x4294, 0xa5, 0xc9, 0x8b, 0x29, 0xb5, 0xea, 0xfa, 0x37);

// {99511B0E-21F3-42d9-A106-826D697963EE}
_DEF_CLSID(CLSID_CDataBase, 0x99511b0e, 0x21f3, 0x42d9, 0xa1, 0x6, 0x82, 0x6d, 0x69, 0x79, 0x63, 0xee);

#endif
